﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LibUsbDotNet.Usb;
using System.Windows.Forms;

namespace StepperProvider
{
    /// <summary>
    /// Класс, позволяющий работать работать с контроллером, управляющим шаговиком
    /// </summary>
    public class StepperProvider : IDisposable
    {
        #region Constants

        private const int CMD_ECHO = 0;      // Возвращаем то же, что и передали сюда - для тестирования
        private const int CMD_GO = 1;        // Начать двигаться на смещение deltaX
        private const int CMD_SETSPEED = 2;  // Установить скорость движения
        private const int CMD_STOP = 3;      // Остановить движение
        private const int CMD_GETPARAMS = 4; // Узнать текущие параметры
        private const int CMD_FLUSH = 5;    // Сброс

        private const int USB_TYPE_STANDARD = (0x00 << 5);
        private const int USB_TYPE_CLASS = (0x01 << 5);
        private const int USB_TYPE_VENDOR = (0x02 << 5);
        private const int USB_TYPE_RESERVED = (0x03 << 5);

        private const int USB_RECIP_DEVICE = 0x00;

        private const int USB_ENDPOINT_IN = 0x80;
        private const int USB_ENDPOINT_OUT = 0x00;

        #endregion


        /// <summary>
        /// Устройство, контролируемое данным UsbDeviceProvider
        /// </summary>
        private UsbDevice device = null;


        /// <summary>
        /// Создать провайдер USB-устройста по имени устройства
        /// </summary>
        /// <param name="deviceName"></param>
        public StepperProvider(string deviceName)
        {
            var mDevList = UsbGlobals.DeviceList;

            foreach (UsbDevice dev in mDevList)
            {
                if (dev.Info.ProductString == deviceName)
                {
                    device = dev;
                    Console.WriteLine(string.Format("StepperProvider: Device found Vid:0x{0:X4} Pid:0x{1:X4} {2} {3} {4}", device.Info.IdVendor, device.Info.IdProduct, device.Info.ManufacturerString, device.Info.ProductString, device.Info.SerialString));
                }
            }

            if (device == null)
                throw new Exception("Usb-устройство с именем " + deviceName.ToString() + " не подключено. Работа программы невозможна");
            else
            {
                if (!device.Open())
                    throw new Exception("Usb-устройство с именем " + deviceName.ToString() + " занято. Работа программы невозможна");                   
            }
        }


        /// <summary>
        /// Завершить работу с устройством
        /// </summary>
        public void Dispose()
        {
            device.Close();
        }


        #region Stepper commands


        public byte[] Echo(int value1, int value2)
        {
            byte[] buffer = new byte[10];
            device.IOControlMessage(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_ECHO,
               value1,
               value2,
               buffer,
               5000);
            return buffer;
        }

        /// <summary>
        /// Поехали на смещение
        /// </summary>
        /// <param name="deltaX">смещение</param>
        /// <param name="isLeft">влево ли двигаться</param>
        public void Go(int delta, bool isLeft)
        {
            device.IOControlMessage(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_GO,
               delta,
               isLeft ? 1 : 0,
               new byte[] { },
               5000);
        }

        /// <summary>
        /// Установить скорость
        /// </summary>
        /// <param name="speed">скорость от 0 до 2500 импульсов в секунду</param>
        public void SetSpeed(int speed)
        {
            device.IOControlMessage(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_SETSPEED,
                speed,
                0,
                new byte[] { },
                5000);
        }

        /// <summary>
        /// Остановить выполнение
        /// </summary>
        public void Stop()
        {
            device.IOControlMessage(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_STOP,
               0,
               0,
               new byte[] { },
               5000);
        }

        /// <summary>
        /// Сброс
        /// </summary>
        public void Flush()
        {
            device.IOControlMessage(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_FLUSH,
               0,
               0,
               new byte[] { },
               5000);
        }

        /// <summary>
        /// Получить от устройства параметры
        /// </summary>
        /// <returns>параметры</returns>
        public byte[] GetParams()
        {
            // getMessage
            byte[] buffer = new byte[10];
            device.IOControlMessage(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_GETPARAMS, 771, 771, buffer, 5000);

            return buffer;
        }

        #endregion
    }
}
